package com.lj.back.manage.scaffold.module.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.lj.back.manage.scaffold.common.enums.ResponseEnum;
import com.lj.back.manage.scaffold.common.enums.UserStatusEnum;
import com.lj.back.manage.scaffold.common.util.Assert;
import com.lj.back.manage.scaffold.common.util.CommonUtil;
import com.lj.back.manage.scaffold.common.util.QueryWrapperUtil;
import com.lj.back.manage.scaffold.module.sys.DO.SysUserDO;
import com.lj.back.manage.scaffold.module.sys.DTO.*;
import com.lj.back.manage.scaffold.module.sys.constant.UserConstant;
import com.lj.back.manage.scaffold.module.sys.dao.SysUserDao;
import com.lj.back.manage.scaffold.module.sys.dao.SysUserRoleDao;
import com.lj.back.manage.scaffold.module.sys.service.SysRoleService;
import com.lj.back.manage.scaffold.module.sys.service.SysUserService;
import com.lj.back.manage.scaffold.module.sys.service.SysUserTokenService;
import com.lj.back.manage.scaffold.module.sys.util.SysCommonUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author lv
 * @version 1.0.0
 */
@Service
@AllArgsConstructor
public class SysUserServiceImpl implements SysUserService {

    private final SysUserDao sysUserDao;

    private final SysRoleService sysRoleService;

    private final SysUserRoleDao sysUserRoleDao;

    private final SysUserTokenService sysUserTokenService;

    private QueryWrapper<SysUserDO> getSysUserBaseQueryWrapper(){
        QueryWrapper<SysUserDO> queryWrapper = new QueryWrapper<>();
        return queryWrapper;
    }

    @Override
    public SysUserDTO getUser(String key){
        QueryWrapper<SysUserDO> wrapper = getSysUserBaseQueryWrapper();
        wrapper.eq("id",key)
                .or()
                .eq("name",key);
        SysUserDO sysUserDO = sysUserDao.selectOne(wrapper);
        Assert.assertNotNull(sysUserDO,ResponseEnum.USER_IS_NULL);
        SysUserDTO sysUserDTO = BeanUtil.copyProperties(sysUserDO, SysUserDTO.class);
        Set<Long> roleIds = listUserRoles(sysUserDO.getId()).stream()
                .map(sysRoleDTO -> sysRoleDTO.getId())
                .collect(Collectors.toSet());
        sysUserDTO.setRoleIds(roleIds);
        return sysUserDTO;
    }

    @Override
    public SysUserDTO getUserByToken(String token) {
        SysUserDO userDO = sysUserDao.selectUserByToken(token);
        Assert.assertNotNull(userDO, ResponseEnum.TOKEN_INVALID);
        return BeanUtil.copyProperties(userDO,SysUserDTO.class);
    }

    @Override
    public Set<String> listUserPermissions(Long userId) {
        Set<SysRoleDTO> roles = listUserRoles(userId);
        Assert.assertNotNull(roles,"用户角色信息异常，请联系管理员");
        //admin用户查询全部
        boolean isAdminRole = roles.stream().anyMatch(sysRoleDTO -> sysRoleDTO.getId() == UserConstant.USER_ADMIN_ID);
        if (isAdminRole){
            return sysRoleService.listRolePermissions(null);
        }
        Set<String> permissionsByUser = new HashSet<>();
        roles.forEach(sysRoleVO -> {
            Set<String> permissions = sysRoleService.listRolePermissions(sysRoleVO.getId());
            if (permissions != null && !permissions.isEmpty()){
                permissionsByUser.addAll(permissions);
            }
        });
        return permissionsByUser;
    }

    @Override
    public Set<SysRoleDTO> listUserRoles(Long userId){
        Set<SysRoleDTO> roles = sysRoleService.listRoleByUser(userId);
        if (CollectionUtil.isEmpty(roles)){
            //设置默认角色
            sysRoleService.addRoleToUser(UserConstant.USER_DEFAULT_ID,userId);
            roles = sysRoleService.listRoleByUser(userId);
        }
        return roles;
    }


    @Override
    public IPage<SysUserDTO> listUsers(SysUserPageQuery pageQuery){
        QueryWrapper<SysUserDO> queryWrapper = QueryWrapperUtil.getPageQueryWrapper(SysUserDO.class, pageQuery,"name","real_name");
        queryWrapper.eq(pageQuery.getStatus() != null,"status",pageQuery.getStatus());
        IPage page = sysUserDao.selectPage(QueryWrapperUtil.getPage(pageQuery), queryWrapper);
        IPage<SysUserDTO> iPage = CommonUtil.pageBeanConvert(page, SysUserDTO.class);
        return iPage;
    }


    @Override
    @Transactional(rollbackFor = Throwable.class)
    public Long addUser(SysUserDTO sysUserDTO) {
        SysUserDO sysUserDO = BeanUtil.copyProperties(sysUserDTO, SysUserDO.class);
        String password = sysUserDTO.getPassword();
        //加密密码
        sysUserDO.setPassword(BCrypt.hashpw(password));
        sysUserDao.insert(sysUserDO);
        Set<Long> roleIds = (sysUserDTO.getRoleIds() == null) ? new HashSet<>() : sysUserDTO.getRoleIds();
        roleIds.add(UserConstant.USER_DEFAULT_ID);
        sysUserDao.insertUserRole(sysUserDO.getId(),sysUserDTO.getRoleIds());
        return sysUserDO.getId();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean updateUser(SysUserUpdateDTO sysUserUpdateDTO){
        //更新用户基础信息
        SysUserDO sysUserDO = BeanUtil.copyProperties(sysUserUpdateDTO, SysUserDO.class);
        SysUserDTO user = SysCommonUtil.getUser();
        String oldPassword = sysUserUpdateDTO.getOldPassword();
        String newPassword = sysUserUpdateDTO.getNewPassword();
        if (StringUtils.isNotBlank(oldPassword) && StringUtils.isNotBlank(newPassword)){
            boolean isSuccess = BCrypt.checkpw(oldPassword,user.getPassword());
            Assert.assertIsTrue(!isSuccess, ResponseEnum.USER_PASSWORD_ERROR);
            sysUserDO.setPassword(BCrypt.hashpw(newPassword));
        }
        sysUserDO.setId(user.getId());
        sysUserDao.updateById(sysUserDO);
        //删除token
        sysUserTokenService.deleteToken(user.getId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean deleteUser(Long userId){
        Assert.assertIsTrue(Objects.equals(userId, UserConstant.USER_ADMIN_ID),"不允许删除admin账户");
        //删除用户角色关联关系
        sysUserRoleDao.deleteUserRoleByUserId(userId);
        //删除用户
        sysUserDao.deleteById(userId);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public boolean resetUserInfo(SysResetUserDTO resetUser){
        SysUserDO user = BeanUtil.copyProperties(resetUser,SysUserDO.class);
        user.setPassword(BCrypt.hashpw(resetUser.getPassword()));
        sysUserDao.updateById(user);
        //删除关联角色
        sysUserRoleDao.deleteUserRoleByUserId(resetUser.getId());
        if (CollectionUtil.isNotEmpty(resetUser.getRoleIds())){
            //新增角色
            sysUserDao.insertUserRole(resetUser.getId(),resetUser.getRoleIds());
        }
        //重置密码  或者锁定用户删除该用户所有token
        if (resetUser.getPassword()!=null || Objects.equals(resetUser.getStatus(), UserStatusEnum.LOCK.getCode())){
            //删除token
            sysUserTokenService.deleteToken(resetUser.getId());
        }
        return true;
    }
}
